package org.dromara.common.social.gitea

import cn.hutool.http.HttpRequest
import io.github.oshai.kotlinlogging.KotlinLogging
import me.zhyd.oauth.cache.AuthStateCache
import me.zhyd.oauth.config.AuthConfig
import me.zhyd.oauth.exception.AuthException
import me.zhyd.oauth.model.AuthCallback
import me.zhyd.oauth.model.AuthToken
import me.zhyd.oauth.model.AuthUser
import me.zhyd.oauth.request.AuthDefaultRequest
import org.dromara.common.core.utils.SpringUtils
import org.dromara.common.json.utils.JsonUtils.parseMap

/**
 * @author LikeYouDo
 */
class AuthGiteaRequest : AuthDefaultRequest {
    companion object {
        private val log = KotlinLogging.logger { }
        val SERVER_URL: String = SpringUtils.getProperty("justauth.type.gitea.server-url")
    }

    /**
     * 设定归属域
     */
    constructor(config: AuthConfig) : super(config, AuthGiteaSource.GITEA)

    constructor(config: AuthConfig, authStateCache: AuthStateCache) : super(
        config,
        AuthGiteaSource.GITEA,
        authStateCache
    )

    override fun getAccessToken(authCallback: AuthCallback): AuthToken? {
        val body = doPostAuthorizationCode(authCallback.code)
        val obj = parseMap(body)!!
        // oauth/token 验证异常
        if (obj.containsKey("error")) {
            throw AuthException(obj.getStr("error_description"))
        }
        // user 验证异常
        if (obj.containsKey("message")) {
            throw AuthException(obj.getStr("message"))
        }
        return AuthToken.builder()
            .accessToken(obj.getStr("access_token"))
            .refreshToken(obj.getStr("refresh_token"))
            .idToken(obj.getStr("id_token"))
            .tokenType(obj.getStr("token_type"))
            .scope(obj.getStr("scope"))
            .build()
    }

    override fun doPostAuthorizationCode(code: String?): String? {
        val request = HttpRequest.post(source.accessToken())
            .form("client_id", config.clientId)
            .form("client_secret", config.clientSecret)
            .form("grant_type", "authorization_code")
            .form("code", code)
            .form("redirect_uri", config.redirectUri)
        val response = request.execute()
        return response.body()
    }

    override fun getUserInfo(authToken: AuthToken?): AuthUser? {
        val body = doGetUserInfo(authToken)
        val obj = parseMap(body)!!
        // oauth/token 验证异常
        if (obj.containsKey("error")) {
            throw AuthException(obj.getStr("error_description"))
        }
        // user 验证异常
        if (obj.containsKey("message")) {
            throw AuthException(obj.getStr("message"))
        }
        return AuthUser.builder()
            .uuid(obj.getStr("sub"))
            .username(obj.getStr("name"))
            .nickname(obj.getStr("preferred_username"))
            .avatar(obj.getStr("picture"))
            .email(obj.getStr("email"))
            .token(authToken)
            .source(source.toString())
            .build()
    }
}
